﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml;

namespace WenSkin.WenXmlConfig
{
    public class ConfigXmlParsing
    {

        public ConfigXmlParsing() : this("WenAutoConfig")
        {
        }
        public ConfigXmlParsing(string xmlName)
        {
            XmlName = xmlName;
            OpenXmlConfig();
        }

        #region 私有属性

        private ConfigXmlGroupCollection group;

        #endregion

        #region 公有属性

        public ConfigXmlGroupCollection Group => group ??= new ConfigXmlGroupCollection(this);
        public string XmlName { get; set; }

        #endregion


        //打开配置文件
        public void OpenXmlConfig()
        {
            string path = $"{Application.StartupPath}\\{XmlName}.xml";
            OpenXmlConfig(path);
        }
        public void OpenXmlConfig(string path)
        {
            #region 解析Xml配置文件            
            XmlDocument xml = xmlDocumentOpen(path);

            foreach (XmlNode groupXn in xml.SelectNodes("Xml/Group"))
            {
                ConfigXmlGroup group = new ConfigXmlGroup(this);

                if (groupXn.SelectNodes("Name")[0] is XmlNode configName)
                {
                    group.Name = configName.InnerText;
                }
                if (groupXn.SelectNodes("Info")[0] is XmlNode configInfo)
                {
                    group.Info = configInfo.InnerText;
                }
                if (groupXn.SelectNodes("AllowAdd")[0] is XmlNode configAllowAdd)
                {
                    group.AllowAdd = Convert.ToBoolean(configAllowAdd.InnerText);
                }               
                if (groupXn.SelectNodes("Visible")[0] is XmlNode configVisible)
                {
                    group.Visible = Convert.ToBoolean(configVisible.InnerText);
                }

                if (groupXn.SelectNodes("Value")[0] is XmlNode configValue)
                {
                    foreach (XmlNode xn in configValue.SelectNodes("Item"))
                    {
                        ConfigXmlItem item = new ConfigXmlItem();
                        if (xn.SelectNodes("Name")[0] is XmlNode itemName)
                        {
                            item.Name = itemName.InnerText;
                        }
                        if (xn.SelectNodes("Info")[0] is XmlNode itemInfo)
                        {
                            item.Info = itemInfo.InnerText;
                        }
                        if (xn.SelectNodes("Ecc")[0] is XmlNode itemEcc)
                        {
                            item.Ecc = Convert.ToBoolean(itemEcc.InnerText);
                        }
                        if (xn.SelectNodes("ReadOnly")[0] is XmlNode itemReadOnly)
                        {
                            item.ReadOnly = Convert.ToBoolean(itemReadOnly.InnerText);
                        }
                        if (xn.SelectNodes("Remove")[0] is XmlNode itemRemove)
                        {
                            item.Remove = Convert.ToBoolean(itemRemove.InnerText);
                        }  
                        if (xn.SelectNodes("Visible")[0] is XmlNode itemVisible)
                        {
                            item.Visible = Convert.ToBoolean(itemVisible.InnerText);
                        }
                        if (xn.SelectNodes("Value")[0] is XmlNode itemValue)
                        {
                            if (item.Ecc)
                                item.Value = AES.AesEnDe.AESDecrypt(itemValue.InnerText) ?? "";
                            else
                                item.Value = itemValue.InnerText;
                        }
                        if (xn.SelectNodes("Tip")[0] is XmlNode itemTip)
                        {
                            item.Tip = itemTip.InnerText;
                        }
                        group.Item.Add(item);
                    }
                }
                this.Group.Add(group);
            }

            #endregion
        }
        //检查路径是否存在，不存在保存一下，重建立一次
        private XmlDocument xmlDocumentOpen(string path)
        {
            XmlDocument xml = new XmlDocument();
            if (File.Exists(path))
            {
                xml.Load(path);
                return xml;
            }
            else
            {
                return SaveXmlConfig(path);
            }
        }

        //保存Xml配置文件
        public void SaveXmlConfig()
        {
            string path = $"{Application.StartupPath}\\{XmlName}.xml";
            SaveXmlConfig(path);
        }
        public XmlDocument SaveXmlConfig(string path)
        {
            XmlDocument xml = new XmlDocument();
            #region 保存Xml文档

            StringBuilder sb = new StringBuilder();
            sb.Append("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\r\n");
            sb.Append("<Xml>\r\n");

            foreach (ConfigXmlGroup gr in this.Group)
            {
                sb.Append("  <Group>\r\n");
                sb.Append($"    <Name>{gr.Name}</Name>\r\n");
                sb.Append($"    <Info>{gr.Info}</Info>\r\n");
                sb.Append($"    <AllowAdd>{gr.AllowAdd}</AllowAdd>\r\n");
                sb.Append($"    <Visible>{gr.Visible}</Visible>\r\n");
                sb.Append("    <Value>\r\n");
                foreach (ConfigXmlItem item in gr.Item)
                {
                    sb.Append("      <Item>\r\n");
                    sb.Append($"        <Name>{item.Name}</Name>\r\n");
                    sb.Append($"        <Info>{item.Info}</Info>\r\n");
                    sb.Append($"        <Ecc>{item.Ecc}</Ecc>\r\n");
                    sb.Append($"        <ReadOnly>{item.ReadOnly}</ReadOnly>\r\n");
                    sb.Append($"        <Remove>{item.Remove}</Remove>\r\n");
                    sb.Append($"        <Visible>{item.Visible}</Visible>\r\n");

                    if (item.Ecc)
                        sb.Append($"        <Value>{AES.AesEnDe.AESEncrypt(item.Value)}</Value>\r\n");
                    else
                        sb.Append($"        <Value>{item.Value}</Value>\r\n");

                    sb.Append($"        <Tip>{item.Tip}</Tip>\r\n");

                    sb.Append("      </Item>\r\n");
                }
                sb.Append("    </Value>\r\n");
                sb.Append("  </Group>\r\n");
            }
            sb.Append("</Xml>");

            xml.LoadXml(sb.ToString());
            xml.Save(path);
            return xml;
            #endregion
        }


        public class ConfigXmlGroup
        {
            private ConfigXmlItemCollection item;
            private readonly ConfigXmlParsing owner;

            public ConfigXmlGroup(ConfigXmlParsing owner)
            {
                Name = "";
                Info = "";
                AllowAdd = false;
                Visible = true;
                this.owner = owner;
            }

            public string Name { get; set; }
            public string Info { get; set; }
            public bool AllowAdd { get; set; }
            public bool Visible { get; set; }
            public ConfigXmlItemCollection Item => item ??= new ConfigXmlItemCollection(owner);
        }

        public class ConfigXmlGroupCollection : WenSkin.Controls.WenCollection
        {
            public ConfigXmlGroupCollection(ConfigXmlParsing owner)
            {
                this.owner = owner;
            }
            private readonly ConfigXmlParsing owner;

            public ConfigXmlGroup this[int index] { get => (ConfigXmlGroup)Items[index]; set => Items[index] = value; }
            public ConfigXmlItemCollection this[string str]
            {
                get
                {
                    if (Items.ToArray().ToList().Find(a => ((ConfigXmlGroup)a).Name.ToUpper() == str.ToUpper() || ((ConfigXmlGroup)a).Info.ToUpper() == str.ToUpper()) is ConfigXmlGroup item)
                    {
                        return item.Item;
                    }
                    else
                    {
                        return CustomAdd(str).Item;
                    }
                }
                set
                {
                    if (Items.ToArray().ToList().Find(a => ((ConfigXmlGroup)a).Name.ToUpper() == str.ToUpper() || ((ConfigXmlGroup)a).Info.ToUpper() == str.ToUpper()) is ConfigXmlGroup item)
                    {
                        value.ToArray().ToList().ForEach(a => item.Item.Add(a));
                    }
                }
            }

            public string this[string group, string val]
            {
                get
                {
                    if (Items.ToArray().ToList().Find(a => ((ConfigXmlGroup)a).Name.ToUpper() == group.ToUpper() || ((ConfigXmlGroup)a).Info.ToUpper() == group.ToUpper()) is ConfigXmlGroup item)
                    {
                        if (item.Item.ToArray().ToList().Find(a =>
                              ((ConfigXmlItem)a).Name.ToUpper() == val.ToUpper() ||
                              ((ConfigXmlItem)a).Info.ToUpper() == val.ToUpper())
                            is ConfigXmlItem im
                            )
                        {
                            return im.Value;
                        }
                    }
                    return CustomItem(group, val).Value;
                }
                set
                {
                    if (Items.ToArray().ToList().Find(a => ((ConfigXmlGroup)a).Name.ToUpper() == group.ToUpper() || ((ConfigXmlGroup)a).Info.ToUpper() == group.ToUpper()) is ConfigXmlGroup item)
                    {
                        if (item.Item.ToArray().ToList().Find(a =>
                              ((ConfigXmlItem)a).Name.ToUpper() == val.ToUpper() ||
                              ((ConfigXmlItem)a).Info.ToUpper() == val.ToUpper())
                            is ConfigXmlItem im
                            )
                        {
                            im.Value = value;
                            return;
                        }
                    }
                    CustomItem(group, val).Value = value;
                }
            }

            //查询是否存在自定义组,不存在自动添加
            private ConfigXmlGroup CustomAdd(string groupName)
            {
                if (Items.ToArray().ToList().Find(a =>
                ((ConfigXmlGroup)a).Name == groupName)
                    is ConfigXmlGroup group)
                {
                    return group;
                }
                else
                {
                    group = new ConfigXmlGroup(owner)
                    {
                        Name = groupName,
                        Info = "自定义组"
                    };
                    this.Items.Add(group);
                    owner.SaveXmlConfig();
                    return group;
                }
            }

            //添加自定义设置项
            private ConfigXmlItem CustomItem(string groupName, string itemName)
            {
                ConfigXmlGroup group = CustomAdd(groupName);

                ConfigXmlItem item = new ConfigXmlItem()
                {
                    Name = itemName,
                    Info = "自动添加",
                    Ecc = false,
                    ReadOnly = false,
                    Value = "",
                };
                group.Item.Add(item);
                owner.SaveXmlConfig();
                return item;
            }
        }

        public class ConfigXmlItem
        {
            public ConfigXmlItem()
            {
                Name = "";
                Info = "";
                Ecc = false;
                ReadOnly = false;
                Remove = false;
                Value = "";
                Tip = "";
                Visible = true;
            }

            public string Name { get; set; }
            public string Info { get; set; }
            public bool Ecc { get; set; }
            public bool ReadOnly { get; set; }
            public bool Remove { get; set; }
            public string Value { get; set; }
            public string Tip { get; set; }
            public bool Visible { get; set; }
        }

        public class ConfigXmlItemCollection : WenSkin.Controls.WenCollection
        {
            public ConfigXmlItemCollection(ConfigXmlParsing owner)
            {
                this.owner = owner;
            }
            private readonly ConfigXmlParsing owner;
            public ConfigXmlItem this[int index] { get => (ConfigXmlItem)Items[index]; set => Items[index] = value; }
            public ConfigXmlItem this[string str]
            {
                get
                {
                    if (Items.ToArray().ToList().Find(a => ((ConfigXmlItem)a).Name.ToUpper() == str.ToUpper() || ((ConfigXmlItem)a).Info.ToUpper() == str.ToUpper()) is ConfigXmlItem item)
                    {
                        return item;
                    }
                    else
                    {
                        return CustomItem(str);
                    }
                }
                set
                {
                    if (Items.ToArray().ToList().Find(a => ((ConfigXmlItem)a).Name.ToUpper() == str.ToUpper() || ((ConfigXmlItem)a).Info.ToUpper() == str.ToUpper()) is ConfigXmlItem item)
                    {
                        item = value;
                    }
                }
            }

            //自动添加项
            private ConfigXmlItem CustomItem(string itemName)
            {
                ConfigXmlItem item = new ConfigXmlItem()
                {
                    Name = itemName,
                    Info = "自动添加",
                    Ecc = false,
                    ReadOnly = false,
                    Value = "",
                };
                this.Add(item);
                owner.SaveXmlConfig();
                return item;
            }
        }
    }
}
